//import java.io.*;
import java.util.*;
/**
 *
 * @author Janek
 */
public class Genetyczny {

    /**
     * @param args the command line arguments
     */

    public static void main(String[] args) throws CloneNotSupportedException{

        int populacja, dokladnosc, licznik=0, iter;
        double iksik=0;
        int poczatek = -500;
        int koniec = 500;
        System.out.println("Optymalizacja funkcji Griewangk na przedziele dla kazdego wymiaru <-600,600>\n");
        Scanner wejscie = new Scanner(System.in);
        System.out.println("Podaj wielkosc populacji: ");
        populacja = wejscie.nextInt();
        System.out.println("podaj ilosc iteracji: ");
        iter = wejscie.nextInt();
        System.out.println("podaj dokladnosc: ");
        dokladnosc = wejscie.nextInt();
        System.out.println("doooooooooooooooooooooooooooooooooooooooo:"+dokladnosc);
        int dok;
        dok = Genetyczny.dokladnosc(dokladnosc,poczatek,koniec);
        Populacja popul = new Populacja(populacja,dok,poczatek,koniec);
        popul.pokaz();
        double wynik=0.000;
        //wynik < 11.99
        while(true){
         if(licznik == iter)break;
         licznik++;
        Populacja tymcza = new Populacja(populacja,dok,poczatek,koniec);
        for (int i=0; i<populacja; i++){
           tymcza.chrom[i] = popul.chrom[popul.ruletka()-1].clone();
        }

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>????????????????");
        tymcza.pokaz();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>?????????????????");
        tymcza.wymiana(dok);
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        tymcza.pokaz();
        for (int i=0; i<populacja; i++){
            popul.chrom[i] = tymcza.chrom[i].clone();
        }
        for (int j=0; j<populacja; j++){
            System.out.println("wynik w petli: "+wynik);
            if(wynik < popul.chrom[j].przystosowanie()){

               wynik = popul.chrom[j].przystosowanie();
               iksik = popul.chrom[j].wartosc();
            }
        }
        System.out.println("POPULLLLLLLLLLLL");
        popul.pokaz();
        System.out.println("otttoooooo wynik posredni: "+wynik+"    w punkcie: "+iksik);
        }

    }

    static int dokladnosc(int dok, int pocz, int kon){ // dokladnosc; poczatek; koniec
        int wynik=0;
        int wartosc=0;
        int licznik=0;
        wynik = (kon - pocz) * (int)Math.pow(10, dok);
        while(wynik>wartosc-1){
            licznik++;
            wartosc = (int)Math.pow(2,licznik);
        }
        System.out.println("ilosc bitow chromosomu zalezna od dokladnosci: "+licznik);
        return licznik;
    }
}

class Chromosom implements Cloneable{
    int bit = 8; // ilosc bitow ciągu kodowego
    int [] tab;
    int poczatek;
    int koniec;
    Random generator = new Random();
    int wartosc=0; //odkodowany parametr
    public Chromosom(int bit1){
        bit = bit1;
        tab = new int[bit];
        int licznik = bit-1;
        for (int i=0; i<bit; i++){
            int los = generator.nextInt(2)+1;
            if(los==2) {tab[i] = 1;
                        wartosc += Math.pow(2,licznik);
                        licznik--;}
            else {tab[i] = 0;
                    licznik--;}
        }
    }
    public Chromosom(){
        int licznik = bit-1;
        tab = new int[bit];
        for (int i=0; i<bit; i++){
            int los = generator.nextInt(2)+1;
            if(los==2) {tab[i] = 1;
                        wartosc += Math.pow(2,licznik);
                        licznik--;}
            else {tab[i] = 0;
                    licznik--;}
        }
    }
    //wartosc funkcji celu
    double przystosowanie(){
        double y;
        //funkcja celu
        //y = wartosc();
        //y = ((int)Math.pow(wartosc,2)) - (6*wartosc);
        //y = ((int)Math.pow(wartosc(),2));
        //y = 2*wartosc() - 2;
        //y = 0.5*wartosc()+Math.sin(5*wartosc());
        //y = -Math.pow((wartosc()-5), 2)+12;
        y = wartosc()*Math.sin(Math.sqrt(Math.abs(wartosc())));
        //y = -1*(1/4000 * Math.pow(wartosc(),2) - Math.cos(wartosc())+1);

        return y;
    }

    double wartosc(){
        int wartosc1 = 0;
        double wyn;
        int licznik = bit -1;
        for (int i=0; i<bit; i++){
            //int los = generator.nextInt(2)+1;
            if(this.tab[i]==1){
                        wartosc1 += Math.pow(2,licznik);
                        licznik--;}
            else {
                    licznik--;}
        }
        wyn = poczatek + (wartosc1*(koniec-poczatek))/(Math.pow(2, bit)-1);
        return wyn;
    }

    void set_pocz(int p){
        poczatek = p;
    }

    void set_kon(int k){
        koniec = k;
    }

    void pokaz(int i){
        System.out.println("chromosom nr " + i + ": " + Arrays.toString(tab) + "  jako liczba:" + wartosc());
    }
    void pokaz(){
        System.out.println("chromosom nr : " + Arrays.toString(tab) + "  jako liczba:" + wartosc());
    }


   @Override
   public Chromosom clone() throws CloneNotSupportedException{
       Chromosom chrim = (Chromosom) super.clone();
       chrim.tab = (int[]) tab.clone();
       return chrim;
   }


}

class Populacja implements Cloneable {
    int dok;
    int liczba =4; // rozmiar populacji
    int numer = 0; //numer pokolenia
    int poczatek;
    int koniec;
    //Chromosom [] chrom = new Chromosom[liczba];
    Chromosom [] chrom;
    public Populacja(int licz, int dokladnosc, int pocz, int kon){
        poczatek = pocz;
        koniec = kon;
        dok=dokladnosc;
        liczba = licz;
        chrom = new Chromosom[liczba];
        numer++;
        for (int i=0; i<liczba; i++){
            chrom[i] = new Chromosom(dokladnosc);
            chrom[i].set_pocz(poczatek);
            chrom[i].set_kon(koniec);
        }
    }
    public Populacja(){
        chrom = new Chromosom[liczba];
        numer++;
        for (int i=0; i<liczba; i++){
            chrom[i] = new Chromosom();
            chrom[i].set_pocz(poczatek);
            chrom[i].set_kon(koniec);
        }
    }

    int get_dok(){
        return dok;
    }
    void pokaz(){
        for(int i=0; i<liczba; i++){
            chrom[i].pokaz(i);
            System.out.println("\n");
        }

    }

   double sumap(){ // suma wartosci przystosowania wszystkich osobnikow
       double suma=0;
       for (int i=0; i<liczba; i++){
           suma += this.przystosowanie(i);
       }
       return suma;
   }

   int ruletka(){
       Random generator = new Random();
       double sum=0, x;
       int i=0;
       double rand = generator.nextDouble() * this.sumap();
       //System.out.println("randomize = "+rand);
       while (sum < rand){
           if(i==liczba)break;
           x = this.przystosowanie(i);
           sum += x;
           i++;
       }
       return i;
   }
   //wartosc funkcji pzystosowania -> f(x) = f(x) + min_przystosowanie, jezeli f(x) + min_przystosowanie > 0
   //                              -> f(x) = 0, jezeli <= 0
   double przystosowanie(int i){
       double sum, y;
       y = this.min_przystosowanie();
       sum = Math.abs(y) + chrom[i].przystosowanie();

       //sum = y + chrom[i].przystosowanie();
       if(sum <= 0)sum=0;
       return sum;
   }
   double min_przystosowanie(){
       double ocena=0.0;
       ocena = chrom[0].przystosowanie();
       for (int i=1; i<liczba; i++){
           if(chrom[i].przystosowanie() <= ocena){
               ocena = chrom[i].przystosowanie();
               //System.out.println("przyst: "+ocena);
           }
       }
       return ocena;
   }

   void wymiana(int bit)throws CloneNotSupportedException{
       int bit1 = bit;
       int los1, los2;
       Random generator = new Random();
       for (int i=0; i<liczba; i++){
            if(generator.nextInt(99)+1<=70){
                while(true){
                    if((los1=generator.nextInt(liczba))!=i)break;
                }
                los2 = generator.nextInt(bit1-1)+1;
                this.krzyzmut(i, los1, los2);
            }
       }

   }


   void krzyzmut(int x, int y, int przeciecie)throws CloneNotSupportedException{
       // x oraz y okreslaja indeksy chromosomow na ktorych wykonywana jest operacja krzyzowania
       System.out.println("wlasnie krzyzuje chromosom o nr: "+x+"  z chromosomem o nr: "+y+"  przeciecie: "+przeciecie);
        Populacja popul1 = new Populacja(liczba,dok,poczatek,koniec);
        popul1 = this;
        Chromosom t1 = new Chromosom();
        Chromosom t2 = new Chromosom();
        t1 = this.chrom[x].clone();
        t2 = this.chrom[y].clone();
        System.out.println("Obiekty pomocnicze");
        t1.pokaz();
        t2.pokaz();
        System.out.println("Obiekty pomocnicze");

        for (int i=0; i<przeciecie; i++){
            popul1.chrom[x].tab[i] = t2.tab[i];
            mutuj(popul1.chrom[x],i);
        System.out.println("chrom 0");
            popul1.chrom[x].pokaz();
            popul1.chrom[y].tab[i] = t1.tab[i];
            mutuj(popul1.chrom[y],i);
        System.out.println("chrom 3");
            popul1.chrom[y].pokaz();
        }
        t1 = popul1.chrom[x].clone();
        t2 = popul1.chrom[y].clone();
        System.out.println("Obiekty pomocnicze");
        t1.pokaz();
        t2.pokaz();
        System.out.println("Obiekty pomocnicze");

        System.out.println("tablica zmieniona");


        this.chrom[x] = t1;
        this.chrom[y] = t2;
        

       //return popul1;
    }

   void mutuj(Chromosom ch, int i) throws CloneNotSupportedException{
       Random generator = new Random();
       if(generator.nextInt(100)<=5){
           if (ch.tab[i] == 1)ch.tab[i]=0;else ch.tab[i]=1;
           System.out.println("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzmutowalem!");
        }
   }



}